package com.wdl.report.app.manager.cbt;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.vondear.rxtool.view.RxToast;
import com.wdl.report.app.manager.cbt.callback.BaseConfigCallback;
import com.wdl.report.app.manager.cbt.constant.BluetoothContast;
import com.wdl.report.app.manager.cbt.receiver.BluetoothReceiver;
import com.wdl.report.app.utils.HexUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


public class ClassicBtManager implements BaseConfigCallback {
    private Context mContext;
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothReceiver mBluetoothReceiver;


    private String targetDeviceName;
    private BluetoothSocket targetSocket;
    private InputStream targetInput;
    private OutputStream targetOut;

    private int repeatCount = 0;
    private String lastCmd, lastHandCmd;
    private BluetoothReceiveLisenter bluetoothReceiveLisenter;

    private Long lastReceiveTime = 0L;
    private String needSendCmd = null;

    private boolean deviceWaitingConnect = false;

    private Thread readThread;
    private boolean read = true;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bundle data = msg.getData();
            if (msg.what == 1) {
                String msgShow = data.getString("msg");
                RxToast.error(msgShow);
            } else if (msg.what == 2) {
                String msgShow = data.getString("msg");
                RxToast.normal(msgShow);
            }
        }
    };


    public static ClassicBtManager getInstance() {
        return CbtManagerHolder.MANAGER;
    }

    private static class CbtManagerHolder {
        private static final ClassicBtManager MANAGER = new ClassicBtManager();
    }

    public interface BluetoothReceiveLisenter {
        void onReceiveCmd(String cmd);
    }

    public void setBluetoothReceiveLisenter(BluetoothReceiveLisenter bluetoothReceiveLisenter) {
        this.bluetoothReceiveLisenter = bluetoothReceiveLisenter;
    }


    @Override
    public void onStateSwitch(int state) {
        if (state == BluetoothAdapter.STATE_ON) {
            showNormal("蓝牙启动成功");
//            connectByName(targetDeviceName);
        } else if (state == BluetoothAdapter.STATE_OFF) {
            showError("蓝牙启动失败");
        }
    }

    @Override
    public void onScanStop() {
        showNormal("蓝牙启动成功");
    }


    @Override
    public void onFindDevice(BluetoothDevice device) {
        if (device == null) {
            showError("设备信息异常");
            return;
        }
        if (targetDeviceName == null) {
            showError("设备初始化异常");
            return;
        }
        if (device.getName() != null && device.getName().equals(targetDeviceName)) {
            showNormal("设备查找成功");
            connectDevice(device);
        }
    }

    @Override
    public void onConnect(BluetoothDevice device) {
        deviceWaitingConnect = false;

        showNormal("设备连接成功");

        try {
            this.targetInput = this.targetSocket.getInputStream();
            this.targetOut = this.targetSocket.getOutputStream();
        } catch (IOException e) {
            System.out.println("获取读写流异常");

            return;
        }

        startReadThread();

        if (needSendCmd != null) {
            sendData(needSendCmd);
        }
    }

    @Override
    public void onDisConnect(BluetoothDevice device) {
        if (deviceWaitingConnect) {
            connectByName(targetDeviceName);
        }
    }

    @Override
    public void onBondFail(BluetoothDevice device) {
        connectByName(targetDeviceName);
    }

    public void init(Context context) {
        if (mContext == null && context != null) {
            mContext = context;
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            mBluetoothReceiver = new BluetoothReceiver(mContext, this);
        }
    }

    private static final String ACK = "5AA503880001";

    public void sendAck() {
        sendData(ACK, false);
    }

    public void sendData(String cmd) {
        sendData(cmd, true);
    }

    private long startConnetTime;

    /**
     * 通过设备名称进行连接设备
     *
     * @param deviceName 设备名称
     */
    public void connectByName(String deviceName) {
        if (deviceWaitingConnect && System.currentTimeMillis() - startConnetTime < 10000) {
            showNormal("设备正在连接中，请稍候再试");
            return;
        }

        startConnetTime = System.currentTimeMillis();

        deviceWaitingConnect = true;

        if (deviceName == null || deviceName.length() == 0) {
            showError("蓝牙搜索设备为空");
            return;
        }

        if (mBluetoothAdapter == null) {
            showError("蓝牙初始化失败");
            return;
        }

        this.targetDeviceName = deviceName;

        //如果蓝牙没有开启，则先开启蓝牙
        if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
            return;
        }

        //搜索是否已经有配对的设备了
        Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
        for (BluetoothDevice next : bondedDevices) {
            if (next.getName().equals(deviceName)) {
                connectDevice(next);

                return;
            }
        }

        //启动扫描，若当前正在扫描，则先停止
        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }
        mBluetoothAdapter.startDiscovery();


    }

    public void destory() {
        read = false;
        if (readThread != null) {
            readThread = null;
        }

//        if (targetSocket != null && targetSocket.isConnected()) {
        if (targetSocket != null) {
            try {
                targetSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        targetSocket = null;

        if (targetInput != null) {
            try {
                targetInput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        targetInput = null;

        if (targetOut != null) {
            try {
                targetOut.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        targetOut = null;

        if (mBluetoothReceiver != null) {
            mContext.unregisterReceiver(mBluetoothReceiver);
        }
        mBluetoothReceiver = null;
    }


    /**
     * 重新连接
     */
    private void reconnect() {
        showNormal("设备重新连接");

        destory();

        mBluetoothReceiver = new BluetoothReceiver(mContext, this);

        connectByName(targetDeviceName);
    }


    /**
     * 设备连接
     */
    private void connectDevice(BluetoothDevice device) {

        if (mBluetoothAdapter == null) {

            return;
        }

        if (mBluetoothAdapter.isDiscovering()) {
            mBluetoothAdapter.cancelDiscovery();
        }

        startConnectThread(device);
    }


    private StringBuffer sb = null;

    /**
     * 接收数据线程
     */
    private void startReadThread() {
        read = true;

        readThread = new Thread(() -> {
            sb = null;
            sb = new StringBuffer();
            while (read) {
                lastReceiveTime = System.currentTimeMillis();

                if (targetInput == null) {
                    System.out.println("读取流为空，等待1s");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }

                byte[] buffer = new byte[1024 * 30];
                int bytes;

                try {
                    bytes = targetInput.read(buffer);
                    byte[] temp = new byte[bytes];
                    System.arraycopy(buffer, 0, temp, 0, bytes);
                    String cmdReceive = HexUtil.encodeHexStr(temp).toUpperCase();

                    System.out.println("接收过来的元数据：" + cmdReceive);

//                    cmdReceive = cmdReceive.substring(0, bytes * 2);

                    sb.append(cmdReceive);

                    //开始判断命令
                    if (sb.length() < 4) {
                        continue;
                    }

                    System.out.println("开始接受数据并进行预处理：" + sb.toString());

                    int startIndex = sb.lastIndexOf("A5F1");
                    int endIndex = sb.indexOf("0D0A");

                    //如果没有开始命令 则直接将本数据进行清空
                    if (startIndex < 0) {
                        System.out.println("没有开始命令:" + sb.toString());
                        sb.delete(0, sb.length());
                        continue;
                    }

                    //如果开始命令，大于0 则将之前的命令进行删除，无效命令
                    if (startIndex > 0) {
                        System.out.println("开始命令大于0:" + sb.substring(0, startIndex));

//                        String cmd = sb.substring(0, startIndex);
                        sb.delete(0, startIndex);
                        //在这里进行判断是否全部删除还是只删除前边的命令
//                        int endPos = sb.length()-startIndex<6||!sb.substring(0,6).equals(sb.substring(startIndex,startIndex+6))?
//                                startIndex:sb.length();
//                        sb.delete(0, endPos);
//                        cmd = cmd.equals("0D0A") ? cmd : cmd + "0D0A";
//                        handCmd(cmd);
//                        continue;
                    }

                    //如果结束命令小于0
                    if (endIndex < 0) {
                        continue;
                    }

                    //如果结束命令大于0
                    String cmd = sb.substring(0, endIndex + 4);
                    sb.delete(0, endIndex + 4);
                    handCmd(cmd);

                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("接收到数据:异常:" + e.getMessage());
                }
            }
        });

        readThread.start();
    }

    private void handCmd(String cmd) {
        System.out.println("接收到的命令是:" + cmd);

        //重复命令判断
//        if (cmd.equals(lastCmd) && cmd.equals(lastHandCmd)) {
        if (isEqualCmd(cmd,lastCmd)&& isEqualCmd(cmd,lastHandCmd)) {
            System.out.println("与上条命令相同:" + cmd);

            repeatCount++;
            if (repeatCount == 10 && bluetoothReceiveLisenter != null) {
                sendAck();
                repeatCount = 0;
            }


            return;
        }

        //命令处理
        lastCmd = cmd;
        if (bluetoothReceiveLisenter != null) {
            lastHandCmd = cmd;
            bluetoothReceiveLisenter.onReceiveCmd(cmd);
        }
    }

    private boolean isEqualCmd(String cmd01, String cmd02){
        return cmd01!=null&&cmd02!=null&&cmd01.substring(0,6).equals(cmd02.substring(0,6));
    }

    /**
     * 启动连接设备线程
     */
    private void startConnectThread(BluetoothDevice device) {
        new Thread(() -> {
            try {
                targetSocket = device.createRfcommSocketToServiceRecord(BluetoothContast.BLUETOOTH_UUID);
                if (targetSocket != null && !targetSocket.isConnected()) {
                    targetSocket.connect();
                }
            } catch (Exception e) {
                deviceWaitingConnect = false;
                showError("获取设备信息失败,请重试");

                unpairDevice(device);
            }
        }).start();
    }

    private void unpairDevice(BluetoothDevice device) {
//        try {
//            Method m = device.getClass().getMethod("removeBond", (Class[]) null);
//            m.setAccessible(true);
//            m.invoke(device, (Object[]) null);
//        } catch (Exception e) {
//            System.out.println("移除配对失败！");
//        }
    }

    /**
     * 发送数据
     */
    private void sendData(String cmd, boolean showMsg) {
        System.out.println("准备发送指令：" + cmd);

        if (targetSocket == null || targetOut == null) {
            showError("设备断开连接,请连接成功后重新接收");
            reconnect();
            return;
        }

        List<String> cmds = new ArrayList<>();

        if (readThread != null && readThread.isAlive() && System.currentTimeMillis() - lastReceiveTime > 60000) {
            System.out.println("读取端口读取流正在被占用，发送ack");
            cmds.add(ACK);
        }

        cmds.add(cmd);
        startCmdSendThread(cmds, showMsg);

        // || System.currentTimeMillis() - lastReceiveTime > 5000
        if (readThread == null || !readThread.isAlive()) {
            System.out.println("读取线程已自动销毁，进行重启");

            read = false;

            startReadThread();
        }
    }

    /**
     * 发送指令线程
     *
     * @param cmds
     */
    private void startCmdSendThread(List<String> cmds, boolean showMsg) {


        new Thread(() -> {

            for (String cmd : cmds) {
                System.out.println("发送指令：" + cmd);
                byte[] data = HexUtil.decodeHex(cmd.toCharArray());

                try {
                    targetOut.write(data);

                    if (showMsg) {
                        showNormal("指令发送成功");
                    }
                } catch (IOException e) {
                    showError("指令发送失败,设备重新连接中，请稍后...");

                    needSendCmd = cmd;

                    reconnect();
                }
            }

            needSendCmd = null;

        }).start();
    }

    private void showError(String msg) {
        showMsg(1, msg);
    }

    private void showNormal(String msg) {
        showMsg(2, msg);
    }

    private void showMsg(int what, String msg) {
        Message message = Message.obtain();
        message.what = what;
        Bundle bundle = new Bundle();
        bundle.putString("msg", msg);
        message.setData(bundle);

        handler.sendMessage(message);
    }
}
